﻿
Imports osi.root.constants
Imports osi.root.connector
Imports osi.root.utils
Imports osi.root.procedure
Imports osi.service.convertor

'we can have several different target_dispatcher generic classes,
'which are using the same dispatcher,
'so the target_dispatcher cannot inherit from dispatcher
Partial Public Class target_dispatcher(Of KEY_T As IComparable(Of KEY_T), T)
    Private ReadOnly dispatcher As dispatcher
    Private ReadOnly container As unique_strong_map(Of KEY_T, T)
    Private ReadOnly bytes_key_t As binder(Of Func(Of Byte(), KEY_T), 
                                              target_dispatcher(Of KEY_T, T))

    Shared Sub New()
        bind_default_bytes_conversion()
    End Sub

    Public Sub New(ByVal dispatcher As dispatcher,
                   ByVal container As unique_strong_map(Of KEY_T, T),
                   ByVal bytes_key_t As binder(Of Func(Of Byte(), KEY_T), 
                                                  target_dispatcher(Of KEY_T, T)))
        assert(Not container Is Nothing)
        If dispatcher Is Nothing Then
            Me.dispatcher = dispatcher.default
        Else
            Me.dispatcher = dispatcher
        End If
        Me.container = container
        Me.bytes_key_t = bytes_key_t
    End Sub

    Public Sub New(ByVal container As unique_strong_map(Of KEY_T, T),
                   ByVal bytes_key_t As binder(Of Func(Of Byte(), KEY_T), 
                                                  target_dispatcher(Of KEY_T, T)))
        Me.New(Nothing, container, bytes_key_t)
    End Sub

    Public Sub New(ByVal dispatcher As dispatcher,
                   ByVal container As unique_strong_map(Of KEY_T, T))
        Me.New(dispatcher, container, Nothing)
    End Sub

    Public Sub New(ByVal container As unique_strong_map(Of KEY_T, T))
        Me.New(Nothing, container, Nothing)
    End Sub

    Public Function [get]() As dispatcher
        Return dispatcher
    End Function

    Public Shared Operator +(ByVal this As target_dispatcher(Of KEY_T, T)) As dispatcher
        If this Is Nothing Then
            Return Nothing
        Else
            Return this.get()
        End If
    End Operator

    Public Function register(ByVal action() As Byte,
                             ByVal act As Func(Of command, command, event_comb),
                             Optional ByVal replace As Boolean = False) As Boolean
        Return dispatcher.register(action, act, replace)
    End Function

    Public Function register(ByVal action As SByte,
                             ByVal act As Func(Of command, command, event_comb),
                             Optional ByVal replace As Boolean = False) As Boolean
        Return dispatcher.register(action, act, replace)
    End Function

    Public Function register(ByVal action As Int16,
                             ByVal act As Func(Of command, command, event_comb),
                             Optional ByVal replace As Boolean = False) As Boolean
        Return dispatcher.register(action, act, replace)
    End Function

    Public Function register(ByVal action As Int32,
                             ByVal act As Func(Of command, command, event_comb),
                             Optional ByVal replace As Boolean = False) As Boolean
        Return dispatcher.register(action, act, replace)
    End Function

    Public Function register(ByVal action As String,
                             ByVal act As Func(Of command, command, event_comb),
                             Optional ByVal replace As Boolean = False) As Boolean
        Return dispatcher.register(action, act, replace)
    End Function

    Private Function handle(ByVal i As command,
                            ByVal o As command,
                            ByVal act As Func(Of T, command, command, event_comb)) As event_comb
        assert(Not i Is Nothing)
        assert(Not o Is Nothing)
        assert(Not act Is Nothing)
        Dim ec As event_comb = Nothing
        Return New event_comb(Function() As Boolean
                                  Dim b() As Byte = Nothing
                                  If i.parameter(constants.parameter.name, b) AndAlso
                                     Not isemptyarray(b) AndAlso
                                     bytes_key_t.has_value() Then
                                      Dim k As KEY_T = Nothing
                                      k = (+bytes_key_t)(b)
                                      Dim v As T = Nothing
                                      If container.get(k, v) Then
                                          ec = act(v, i, o)
                                          Return waitfor(ec) AndAlso
                                                 goto_next()
                                      End If
                                  End If
                                  o.attach(constants.response.invalid_request)
                                  Return goto_end()
                              End Function,
                              Function() As Boolean
                                  Return ec.end_result() AndAlso
                                         goto_end()
                              End Function)
    End Function

    Public Function register(ByVal action() As Byte,
                             ByVal act As Func(Of T, command, command, event_comb),
                             Optional ByVal replace As Boolean = False) As Boolean
        If act Is Nothing Then
            Return False
        Else
            Return register(action,
                            Function(i, o) handle(i, o, act),
                            replace)
        End If
    End Function

    Public Function register(ByVal action As String,
                             ByVal act As Func(Of T, command, command, event_comb),
                             Optional ByVal replace As Boolean = False) As Boolean
        Return register(action.to_bytes(), act, replace)
    End Function

    Public Function register(ByVal action As Int32,
                             ByVal act As Func(Of T, command, command, event_comb),
                             Optional ByVal replace As Boolean = False) As Boolean
        Return register(action.to_bytes(), act, replace)
    End Function

    Public Function register(ByVal action As Int16,
                             ByVal act As Func(Of T, command, command, event_comb),
                             Optional ByVal replace As Boolean = False) As Boolean
        Return register(action.to_bytes(), act, replace)
    End Function

    Public Function register(ByVal action As SByte,
                             ByVal act As Func(Of T, command, command, event_comb),
                             Optional ByVal replace As Boolean = False) As Boolean
        Return register(action.to_bytes(), act, replace)
    End Function

    Public Function [erase](ByVal action() As Byte) As Boolean
        Return dispatcher.erase(action)
    End Function

    Public Function [erase](ByVal action As String) As Boolean
        Return dispatcher.erase(action)
    End Function

    Public Function [erase](ByVal action As Int32) As Boolean
        Return dispatcher.erase(action)
    End Function

    Public Function [erase](ByVal action As Int16) As Boolean
        Return dispatcher.erase(action)
    End Function

    Public Function [erase](ByVal action As SByte) As Boolean
        Return dispatcher.erase(action)
    End Function
End Class
